指针参数提供了一种机制,函数可以通过该机制修改参数值。常用的指针传递(pass by pointer)模式使用指针函数参数,该参数获取调用者传递给它的 某个存储位置的地址值。例如,调用者可以传递其局部变量之一的地址。通过在函数内部取消引用(解引用)指针参数,函数可以修改其指向的存储位置处的值。
我们已经看到了与数组参数类似的功能,其中数组函数参数获取传递数组的基地址的值(该参数引用与其参数相同的数组元素集),并且该函数可以修改存储的值在数组中。一般来说,可以通过将指针参数传递给指向调用者作用域中的内存位置的函数来应用相同的想法。
pass by value
C 中的所有参数均按值传递并遵循按值传递语义:形参获取其实参值的副本,并且修改参数的值不会更改其参数的值。当传递基本类型值时,例如变量的值int
,函数参数会获取其参数值(特定值)的副本 int
,并且更改存储在参数中的值无法更改存储在其参数中的值。
在指针传递(pass-by-pointer)模式中,形参参数仍然获取其实参参数的值,但传递的是 地址的值。就像传递基类型一样,更改指针参数的值不会更改其参数的值(即,将参数分配为指向不同的地址不会更改参数的地址值)。但是,通过取消引用指针参数,函数可以更改参数及其实参所引用的内存内容;通过指针参数,函数可以进行变量内容修改,即使当前函数返回以后,这些修改调用者函数仍然可见。
以下是实现和调用带有传递指针参数的函数的步骤,每一步的代码示例如下:
-
将函数参数声明为指向变量类型的指针:
/* input: an int pointer that stores the address of a memory * location that can store an int value (it points to an int) */ int change_value(int *input) {
-
进行函数调用时,传入变量的地址作为参数:
int x; change_value(&x);
在前面的示例中,由于参数的类型是
int *
,因此必须传递int
类型变量的地址。 -
在函数体内,取消引用指针参数以更改参数的值:
*input = 100; // the location input points to (x's memory) is assigned 100
接下来,让我们检查一个更大的示例程序:
#include <stdio.h>
int change_value(int *input);
int main(void) {
int x;
int y;
x = 30;
y = change_value(&x);
printf("x: %d y: %d\n", x, y); // prints x: 100 y: 30
return 0;
}
/*
* changes the value of the argument
* input: a pointer to the value to change
* returns: the original value of the argument
*/
int change_value(int *input) {
int val;
val = *input; /* val gets the value input points to */
if (val < 100) {
*input = 100; /* the value input points to gets 100 */
} else {
*input = val * 2;
}
return val;
}
运行时,输出为:
x: 100 y: 30
图 1显示了在 中执行 return 之前的调用堆栈change_value
。
图 1. 从 change_value 返回之前的调用栈快照。
输入参数获取其参数值的副本(x
的地址)。在main函数调用时x
的值为30。在 change_value
函数内部,参数被解引用(取消引用,取地址对应的值),将值 100 分配给参数指向的内存位置(*input = 100;
意思是“input
指向的位置设置为值 100”)。由于参数存储main
函数堆栈帧中局部变量的地址,因此通过取消引用参数,可以更改调用者局部变量中存储的值。当函数返回时,参数的值反映了通过指针参数对其所做的更改(main
函数中的x的值被change_value
函数通过input
参数修改为 100)。